<template>
  <div class="realtime-data-card">
    <div class="realtime-header">
      实时运动数据
      <button class="realtime-btn" @click="toggleDevice">
        {{ deviceConnected ? '断开设备' : '连接设备' }}
      </button>
      <button class="realtime-btn" @click="isRunning ? endRun() : startRun()">
        {{ isRunning ? '结束运动' : '开始运动' }}
      </button>
    </div>
    <div class="realtime-content">
      <div class="device-status">
        {{ deviceConnected ? '设备已连接（模拟）' : '设备未连接' }}
      </div>
      <div id="amap-container"></div>
      <div v-if="errorMsg" class="error-msg">{{ errorMsg }}</div>
      <div class="realtime-stats">
        <div>距离：{{ (distance / 1000).toFixed(2) }} km</div>
        <div>用时：{{ formatDuration(duration) }}</div>
        <div>消耗：{{ calories.toFixed(0) }} kcal</div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { onMounted, ref, defineEmits } from 'vue'
import request from '@/utils/request'

const emit = defineEmits(['realtime-update'])
const errorMsg = ref('')
const amapKey = 'f0bd8437b222d831cf4d06bd7d34beae' // 你的高德key
const isRunning = ref(false)
const trackId = ref(null)
const trackPoints = ref([])
const distance = ref(0)
const duration = ref(0)
const calories = ref(0)
const userWeight = ref(70) // 默认70kg，后续用接口获取
const heartRate = ref(0)
const deviceConnected = ref(false)
let timer = null
let durationTimer = null
let map = null
let polyline = null
let startTime = null
let watchId = null

async function fetchLatestWeight() {
  try {
    const res = await fetch('/sport/weight/', { method: 'GET' })
    const data = await res.json()
    if (Array.isArray(data) && data.length > 0) {
      userWeight.value = data[0].weight // 取最新一条体重
    }
  } catch (e) {
    // 获取失败时保持默认体重
  }
}

function loadAmapScript(key) {
  return new Promise((resolve, reject) => {
    if (window.AMap) return resolve()
    const script = document.createElement('script')
    script.type = 'text/javascript'
    script.src = `https://webapi.amap.com/maps?v=2.0&key=${key}`
    script.onload = resolve
    script.onerror = reject
    document.head.appendChild(script)
  })
}

function initMapWithGeolocation() {
  if (!window.AMap) {
    errorMsg.value = '地图加载失败，请检查网络或API Key'
    return
  }
  map = new window.AMap.Map('amap-container', {
    zoom: 17,
  })
  map.plugin('AMap.Geolocation', function () {
    const geolocation = new window.AMap.Geolocation({
      enableHighAccuracy: true,
      timeout: 10000,
      showMarker: true,
      showCircle: true,
      panToLocation: true,
      zoomToAccuracy: true
    })
    map.addControl(geolocation)
    geolocation.getCurrentPosition(function (status, result) {
      if (status === 'complete') {
        if (result && result.position) {
          map.setCenter(result.position)
        }
      } else {
        errorMsg.value = '定位失败：' + result.message
      }
    })
  })
}

function getCurrentPosition() {
  return new Promise((resolve, reject) => {
    if (!window.AMap) return reject('AMap未加载')
    const geolocation = new window.AMap.Geolocation({ enableHighAccuracy: true })
    geolocation.getCurrentPosition(function (status, result) {
      if (status === 'complete' && result && result.position) {
        resolve({ lat: result.position.lat, lng: result.position.lng })
      } else {
        reject(result && result.message ? result.message : '定位失败')
      }
    })
  })
}

function toggleDevice() {
  deviceConnected.value = !deviceConnected.value
}

async function startRun() {
  if (!deviceConnected.value) {
    errorMsg.value = '请先连接设备'
    return
  }
  try {
    const res = await request.post('/sport/create_track/', { name: '运动轨迹' })
    trackId.value = res.track_id
    isRunning.value = true
    trackPoints.value = []
    distance.value = 0
    duration.value = 0
    calories.value = 0
    startTime = Date.now()
    await collectAndUpload() // 立即采集一次
    // 用watchPosition替换setInterval，获得更连续的轨迹点
    if (window.AMap) {
      const geolocation = new window.AMap.Geolocation({ enableHighAccuracy: true })
      watchId = geolocation.watchPosition(function(status, result) {
        if (status === 'complete' && result && result.position) {
          handleNewPoint({ lat: result.position.lat, lng: result.position.lng })
        }
      })
    }
    // 用时每秒刷新
    durationTimer = setInterval(() => {
      duration.value = Math.floor((Date.now() - startTime) / 1000)
    }, 1000)
  } catch (e) {
    errorMsg.value = '创建轨迹失败：' + e
  }
}

function handleNewPoint(pos) {
  const now = Date.now()
  const point = { lat: pos.lat, lng: pos.lng, timestamp: now }
  trackPoints.value.push(point)
  drawPolyline(trackPoints.value)
  distance.value = calcDistance(trackPoints.value)
  calories.value = calcCalories(distance.value)
  emit('realtime-update', {
    distance: distance.value,
    duration: duration.value,
    calories: calories.value,
    heartRate: heartRate.value
  })
  // 上传到后端
  request.post('/sport/upload_track_point/', {
    track_id: trackId.value,
    lat: pos.lat,
    lng: pos.lng,
    timestamp: new Date(now).toISOString()
  })
}

async function collectAndUpload() {
  try {
    const pos = await getCurrentPosition()
    handleNewPoint(pos)
  } catch (e) {
    errorMsg.value = '采集定位失败：' + e
  }
}

async function endRun() {
  if (watchId && window.AMap && window.AMap.Geolocation) {
    const geolocation = new window.AMap.Geolocation({ enableHighAccuracy: true })
    geolocation.clearWatch(watchId)
    watchId = null
  }
  clearInterval(durationTimer)
  isRunning.value = false
  try {
    await request.post('/sport/end_track/', {
      track_id: trackId.value
    })
  } catch (e) {
    errorMsg.value = '结束运动失败：' + e
  }
}

function drawPolyline(points) {
  if (!map || !window.AMap) return
  if (polyline) {
    map.remove(polyline)
  }
  if (points.length < 2) return
  // 按时间排序
  const sortedPoints = points.slice().sort((a, b) => a.timestamp - b.timestamp)
  polyline = new window.AMap.Polyline({
    path: sortedPoints.map(p => [p.lng, p.lat]),
    strokeColor: '#3366FF',
    strokeWeight: 5
  })
  map.add(polyline)
  // 地图自动平移到最新点
  const last = sortedPoints[sortedPoints.length - 1]
  map.setCenter([last.lng, last.lat])
}

function calcDistance(points) {
  if (points.length < 2) return 0
  let total = 0
  for (let i = 1; i < points.length; i++) {
    const prev = points[i - 1]
    const curr = points[i]
    const d = getDistance(prev, curr)
    // 过滤异常点（0.5米<d<50米）
    if (d > 0.5 && d < 50) total += d
  }
  return total
}
function getDistance(p1, p2) {
  const rad = Math.PI / 180
  const lat1 = p1.lat * rad, lat2 = p2.lat * rad
  const a = lat1 - lat2
  const b = (p1.lng - p2.lng) * rad
  const s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) +
    Math.cos(lat1)*Math.cos(lat2)*Math.pow(Math.sin(b/2),2)))
  return s * 6378137 // 地球半径，单位米
}

function calcCalories(distance) {
  // 体重(kg) * 距离(km) * 1.036
  return userWeight.value * (distance / 1000) * 1.036
}

function formatDuration(sec) {
  const m = Math.floor(sec / 60)
  const s = sec % 60
  return `${m}分${s}秒`
}

onMounted(async () => {
  try {
    await loadAmapScript(amapKey)
    initMapWithGeolocation()
    await fetchLatestWeight()
    // 开发测试：运动时每5秒模拟心率
    setInterval(() => {
      if (isRunning.value) {
        heartRate.value = 80 + Math.round(Math.random() * 30)
        emit('realtime-update', {
          distance: distance.value,
          duration: duration.value,
          calories: calories.value,
          heartRate: heartRate.value
        })
      }
    }, 5000)
  } catch (e) {
    errorMsg.value = '地图加载失败，请检查网络或API Key'
  }
})
</script>

<style scoped>
.realtime-data-card {
  background: #fff;
  border-radius: 16px;
  box-shadow: 0 2px 8px rgba(114,46,209,0.08);
  padding: 24px;
  min-height: 260px;
  display: flex;
  flex-direction: column;
}
.realtime-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 18px;
  color: #722ed1;
  font-weight: bold;
  margin-bottom: 12px;
}
.realtime-btn {
  background: linear-gradient(90deg, #a18cd1 0%, #fbc2eb 100%);
  color: #fff;
  border: none;
  border-radius: 16px;
  padding: 6px 18px;
  font-size: 15px;
  font-weight: bold;
  cursor: pointer;
}
.realtime-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
}
.device-status {
  color: #faad14;
  font-size: 15px;
}
#error-msg {
  color: #f56c6c;
  margin-top: 16px;
}
#amap-container {
  width: 100%;
  height: 480px;
  border-radius: 12px;
  box-shadow: 0 2px 8px #0001;
}
.realtime-stats {
  margin-top: 16px;
  display: flex;
  gap: 32px;
  font-size: 16px;
  color: #333;
}
</style> 